/*
* Copyright 2009
* DedaSys LLC - http://www.dedasys.com
*
* Author: David N. Welton <davidw@dedasys.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.hecl.files;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
//#if javaversion >= 1.5
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.Socket;
import java.net.InetSocketAddress;
//#else
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.io.file.FileConnection;
import javax.microedition.io.file.FileSystemRegistry;
//#endif
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import org.hecl.DoubleThing;
import org.hecl.HashThing;
import org.hecl.HeclException;
import org.hecl.Interp;
import org.hecl.IntThing;
import org.hecl.ListThing;
import org.hecl.LongThing;
import org.hecl.ObjectThing;
import org.hecl.Operator;
import org.hecl.StringThing;
import org.hecl.Thing;
/**
* The <code>FileCmds</code> class implements various file commands -
* most importantly, open, but also various operations to check
* whether a file exists, is readable, is a directory, and so on.
*
* @author <a href="mailto:davidw@dedasys.com">David N. Welton</a>
* @version 1.0
*/
public class FileCmds extends Operator {
public static final int OPEN = 1;
public static final int SOCKET = 5;
public static final int READABLE = 10;
public static final int WRITABLE = 20;
public static final int HIDDEN = 30;
public static final int EXISTS = 40;
public static final int DELETE = 50;
public static final int SIZE = 60;
public static final int NAME = 70;
public static final int PATH = 71;
public static final int ABSPATH = 72;
public static final int CANONPATH = 73;
public static final int ISABSOLUTE = 74;
public static final int MTIME = 80;
public static final int ISDIRECTORY = 90;
public static final int ISOPEN = 100;
public static final int LIST = 110;
public static final int MKDIR = 120;
public static final int RENAME = 130;
public static final int TRUNCATE = 140;
public static final int LISTROOTS = 150;
public static final int DU = 160;
public static final int FILESPLIT = 170;
public static final int FILEJOIN = 180;
public static final int SOURCE = 190;
public static final int CURRENTFILE = 200;
public static final int CD = 210;
public static final int GETCWD = 220;
public Thing operate(int cmd, Interp interp, Thing[] argv)
throws HeclException {
String fname = null;
/* These commands are platform agnostic - we'll handle them first. */
switch(cmd) {
/* Note that FILESPLIT is much more platform dependent, so
it is below, in the two sections of ifdef'ed code. */
case FILEJOIN: {
Vector filenamelist = ListThing.get(argv[1]);
/* Takes a list like {a b c} and converts it to a
filename such as a/b/c. */
StringBuffer res = new StringBuffer("");
boolean first = true;
for (int i = 0; i < filenamelist.size(); i++) {
if (first == false) {
res.append(Interp.fileseparator);
} else {
/* FIXME - broken on windows */
if (!filenamelist.elementAt(i).toString().equals("/")) {
first = false;
}
}
res.append(filenamelist.elementAt(i).toString());
}
return new Thing(res.toString());
}
case SOURCE: {
HeclFileUtils.sourceFile(interp, argv[1].toString());
return null;
}
case CURRENTFILE: {
return interp.currentFile;
}
case GETCWD:
return new Thing(System.getProperty("user.dir"));
case CD: {
//#if javaversion >= 1.5
return new Thing(System.setProperty("user.dir", argv[1].toString()));
//#endif
}
}
/* 'Regular' Java uses File, J2ME uses FileConnection. */
//#if javaversion >= 1.5
File tfile = null;
if (cmd != LISTROOTS && cmd != SOCKET) {
fname = StringThing.get(argv[1]);
tfile = new File(fname);
}
//#else
FileConnection fconn = null;
if (cmd != LISTROOTS && cmd != SOCKET) {
fname = StringThing.get(argv[1]);
try {
fconn = (FileConnection)Connector.open(fname);
} catch (IOException e) {
throw new HeclException("IO Exception in " +
argv[0].toString() + ": " + e.toString());
}
}
//#endif
//#if javaversion >= 1.5
switch(cmd) {
case OPEN: {
boolean write = false;
if (argv.length == 3) {
String perms = argv[2].toString();
if (perms.indexOf('w') > -1) {
write = true;
}
}
HeclChannel retval;
try {
if (write) {
retval = new HeclChannel(new DataOutputStream(new FileOutputStream(new File(fname))));
} else {
retval = new HeclChannel(new DataInputStream(new FileInputStream(new File(fname))));
}
} catch (IOException ioe) {
throw new HeclException("Error opening '" + fname + "' :" + ioe.toString());
}
return ObjectThing.create(retval);
}
case SOCKET: {
InetSocketAddress isa = null;
try {
isa = new InetSocketAddress(argv[1].toString(), IntThing.get(argv[2]));
Socket sock = new Socket();
sock.connect(isa);
HeclChannel retval = new HeclChannel(new DataInputStream(sock.getInputStream()),
new DataOutputStream(sock.getOutputStream()));
return ObjectThing.create(retval);
} catch (IOException ioe) {
throw new HeclException("Error opening: " + isa + " " + ioe.toString());
}
}
case READABLE:
{
/* if (argv.length == 3) {
boolean readable = IntThing.get(argv[2]) == 1;
fconn.setReadable(readable);
} */
return IntThing.create(tfile.canRead());
}
case WRITABLE:
{
/* if (argv.length == 3) {
boolean writable = IntThing.get(argv[2]) == 1;
fconn.setWritable(writable);
} */
return IntThing.create(tfile.canWrite());
}
case HIDDEN:
{
/* if (argv.length == 3) {
boolean hidden = IntThing.get(argv[2]) == 1;
fconn.setHidden(hidden);
} */
return IntThing.create(tfile.isHidden());
}
case EXISTS:
return IntThing.create(tfile.exists());
case DELETE:
return IntThing.create(tfile.delete());
case SIZE:
return LongThing.create(tfile.length());
case NAME:
return new Thing(tfile.getName());
case PATH:
return new Thing(tfile.getPath());
case ABSPATH:
return new Thing(tfile.getAbsolutePath());
case CANONPATH:
try {
return new Thing(tfile.getCanonicalPath());
}
catch(Exception e) {
throw new HeclException("I/O error for file '"
+tfile.toString()+",: "+
e.toString());
}
case ISABSOLUTE:
return IntThing.create(tfile.isAbsolute());
case MTIME:
return LongThing.create(tfile.lastModified());
case ISDIRECTORY:
return IntThing.create(tfile.isDirectory());
case ISOPEN:
throw new HeclException("not implemented");
case LIST: {
Vector v = new Vector();
String[] filenames = tfile.list();
for (int i = 0; i < filenames.length; i++) {
v.addElement(new Thing(filenames[i]));
}
return ListThing.create(v);
}
case LISTROOTS: {
Vector v = new Vector();
File[] roots = File.listRoots();
for (int i = 0; i < roots.length; i++) {
v.addElement(new Thing(roots[i].getName()));
}
return ListThing.create(v);
}
case MKDIR: {
tfile.mkdir();
return new Thing(fname);
}
case RENAME: {
tfile.renameTo(new File(argv[2].toString()));
return argv[2];
}
case TRUNCATE: {
/* FIXME */
throw new HeclException("not implemented");
}
case DU: {
//#if javaversion >= 1.6
Hashtable du = new Hashtable();
du.put("total", LongThing.create(tfile.getTotalSpace()));
du.put("used", LongThing.create(tfile.getUsableSpace()));
return HashThing.create(du);
//#else
throw new HeclException("not implemented");
//#endif
}
case FILESPLIT: {
Vector resultv = new Vector();
Vector reversed = new Vector();
File fn = new File(fname);
File pf = fn.getParentFile();
String fns;
String pfs;
/* Walk through all elements, compare the element with
* its parent, and tack the difference onto the
* Vector. */
String ss = null;
while (pf != null) {
fns = fn.toString();
pfs = pf.toString();
ss = fns.substring(pfs.length(), fns.length());
/* The 'diff' operation leaves path components
* with a leading slash. Remove it. */
if (ss.charAt(0) == File.separatorChar) {
ss = ss.substring(1, ss.length());
}
reversed.addElement(new Thing(ss));
fn = pf;
pf = pf.getParentFile();
}
reversed.addElement(new Thing(fn.toString()));
/* Ok, now we correct the order of the list by
* reversing it. */
int j = 0;
for (int i = reversed.size() - 1; i >= 0 ; i --) {
Thing t = (Thing)reversed.elementAt(i);
resultv.addElement(t);
j ++;
}
return ListThing.create(resultv);
}
default:
throw new HeclException("Unknown file command '"
+ argv[0].toString() + "' with code '"
+ cmd + "'.");
}
//#else
try {
switch(cmd) {
case OPEN: {
boolean write = false;
if (argv.length == 3) {
String perms = argv[2].toString();
if (perms.indexOf('w') > -1) {
write = true;
}
}
HeclChannel retval;
if (write) {
if (!fconn.exists()) {
fconn.create();
}
retval = new HeclChannel(fconn.openDataOutputStream());
} else {
retval = new HeclChannel(fconn.openDataInputStream());
}
return ObjectThing.create(retval);
}
case SOCKET: {
String uri = "socket://" + argv[1].toString() + ":" + argv[2].toString();
try {
StreamConnection sc = (StreamConnection) Connector.open(uri);
HeclChannel retval = new HeclChannel(new DataInputStream(sc.openInputStream()),
new DataOutputStream(sc.openOutputStream()));
return ObjectThing.create(retval);
} catch (IOException ioe) {
throw new HeclException("Error opening: " + uri + " " + ioe.toString());
}
}
case READABLE:
{
if (argv.length == 3) {
boolean readable = IntThing.get(argv[2]) == 1;
fconn.setReadable(readable);
}
return IntThing.create(fconn.canRead());
}
case WRITABLE:
{
if (argv.length == 3) {
boolean writable = IntThing.get(argv[2]) == 1;
fconn.setWritable(writable);
}
return IntThing.create(fconn.canWrite());
}
case HIDDEN:
{
if (argv.length == 3) {
boolean hidden = IntThing.get(argv[2]) == 1;
fconn.setHidden(hidden);
}
return IntThing.create(fconn.isHidden());
}
case EXISTS:
{
return IntThing.create(fconn.exists());
}
case DELETE:
{
fconn.delete();
return Thing.emptyThing();
}
case SIZE:
{
return LongThing.create(fconn.fileSize());
}
case NAME:
{
return new Thing(fconn.getName());
}
case MTIME:
{
return LongThing.create(fconn.lastModified());
}
case ISDIRECTORY:
{
return IntThing.create(fconn.isDirectory());
}
case ISOPEN:
{
return IntThing.create(fconn.isOpen());
}
case LIST: {
Vector v = new Vector();
for (Enumeration e = fconn.list(); e.hasMoreElements();) {
v.addElement(new Thing((String)e.nextElement()));
}
return ListThing.create(v);
}
case LISTROOTS: {
Vector v = new Vector();
for (Enumeration e = FileSystemRegistry.listRoots(); e.hasMoreElements();) {
v.addElement(new Thing((String)e.nextElement()));
}
return ListThing.create(v);
}
case MKDIR: {
fconn.mkdir();
return new Thing(fname);
}
case RENAME: {
fconn.rename(argv[2].toString());
return argv[2];
}
case TRUNCATE: {
fconn.truncate(LongThing.get(argv[2]));
}
case DU: {
Hashtable du = new Hashtable();
du.put("total", LongThing.create(fconn.totalSize()));
du.put("used", LongThing.create(fconn.usedSize()));
return HashThing.create(du);
}
case FILESPLIT: {
/* This isn't very good, but it's basically the *
best we can do with what's available on mobile
devices. */
return ListThing.stringSplit(fname, Interp.fileseparator);
}
default:
throw new HeclException("Unknown file command '"
+ argv[0].toString() + "' with code '"
+ cmd + "'.");
}
} catch (IOException e) {
throw new HeclException("IO Exception: " +
HeclException.argvToString(argv) + " : " + e.toString());
}
//#endif
}
public static void load(Interp ip) throws HeclException {
Operator.load(ip,cmdtable);
}
public static void unload(Interp ip) throws HeclException {
Operator.unload(ip,cmdtable);
}
protected FileCmds(int cmdcode,int minargs,int maxargs) {
super(cmdcode,minargs,maxargs);
}
private static Hashtable cmdtable = new Hashtable();
static {
try {
cmdtable.put("open", new FileCmds(OPEN,1,2));
cmdtable.put("socket", new FileCmds(SOCKET,2,2));
cmdtable.put("file.readable", new FileCmds(READABLE,1,2));
cmdtable.put("file.writable", new FileCmds(WRITABLE,1,2));
cmdtable.put("file.hidden", new FileCmds(HIDDEN,1,2));
cmdtable.put("file.exists", new FileCmds(EXISTS,1,1));
cmdtable.put("file.size", new FileCmds(SIZE,1,1));
cmdtable.put("file.name", new FileCmds(NAME,1,1));
//#if javaversion >= 1.6
cmdtable.put("file.path", new FileCmds(PATH,1,1));
cmdtable.put("file.absolutepath", new FileCmds(ABSPATH,1,1));
cmdtable.put("file.canonicalpath", new FileCmds(CANONPATH,1,1));
cmdtable.put("file.isabsolute", new FileCmds(ISABSOLUTE,1,1));
//#endif
cmdtable.put("file.mtime", new FileCmds(MTIME,1,1));
cmdtable.put("file.isdirectory", new FileCmds(ISDIRECTORY,1,1));
cmdtable.put("file.isopen", new FileCmds(ISOPEN,1,1));
cmdtable.put("file.delete", new FileCmds(DELETE,1,1));
cmdtable.put("file.mkdir", new FileCmds(MKDIR,1,1));
cmdtable.put("file.truncate", new FileCmds(TRUNCATE,1,1));
cmdtable.put("file.rename", new FileCmds(RENAME,2,2));
cmdtable.put("file.list", new FileCmds(LIST,1,1));
cmdtable.put("file.devs", new FileCmds(LISTROOTS,0,0));
cmdtable.put("file.du", new FileCmds(DU,1,1));
cmdtable.put("file.split", new FileCmds(FILESPLIT,1,1));
cmdtable.put("file.join", new FileCmds(FILEJOIN,1,1));
cmdtable.put("source", new FileCmds(SOURCE,1,1));
cmdtable.put("file.current", new FileCmds(CURRENTFILE,0,0));
cmdtable.put("file.getcwd", new FileCmds(GETCWD,0,0));
cmdtable.put("file.cd", new FileCmds(CD,1,1));
} catch (Exception e) {
e.printStackTrace();
System.out.println("Can't create file commands.");
}
}
}